import { Color, Object3D, Vector3 } from "three";
import { EntityConfig } from "./Entity";
import Person from "../Entitys/Person";
import { gsap } from "gsap";
import NPC from "src/Entitys/NPC";
import Bullet from "../Entitys/Bullet";

export default class Troop {
  group: Object3D = new Object3D();

  config: EntityConfig;
  constructor(_config: EntityConfig) {
    this.config = _config;
    this.GeneratingCoord();
    this.Behavior();
  }

  sum = 0;
  space = 0.2;
  async AddPerson() {
    let person = new Person(this.config, this);
    await person.Builder();

    this.group.add(person.model);
    this.sum++;
    gsap.to(world, { duration: 1.5, cameraMagnify: 1 + this.sum / 100 });
    let pos = this.personGoord[this.sum - 2];
    if (pos) {
      person.model.position.set(pos[0] * this.space, person.model.position.y, pos[1] * this.space);
    }
  }

  behaviors = ["EveryOneLookAtNearest", "Attack"];
  Behavior() {
    this.behaviors.forEach((m) => {
      render.addClockEvent(m, this[m].bind(this));
    });
  }

  Regroup() {
    for (let i = 0; i < this.group.children.length; i++) {
      let m = this.group.children[i];

      let pos = this.personGoord[i - 1];
      if (pos) {
        gsap.to(m.position, {
          duration: 0.3,
          x: pos[0] * this.space,
          y: m.userData.pos.target.y,
          z: pos[1] * this.space,
        });
      }
    }
  }

  personGoord = [];
  GeneratingCoord() {
    let turnsNum = -1;
    let x = 0,
      y = 0;

    for (let i = 1; i < 20; i++) {
      let group = i % 4 == 0;
      let ordinate = i % 2 != 0;
      if (ordinate) {
        y = turnsNum;
        x = 0;
      } else {
        x = turnsNum;
        turnsNum = -turnsNum;
        y = 0;
      }
      let v2 = [x, y, turnsNum];

      let preV2 = this.personGoord[this.personGoord.length - 1] || [0, 0];
      let ly = ordinate ? v2[1] : preV2[1],
        lx = ordinate ? preV2[0] : v2[0];

      if (Math.abs(lx) != Math.abs(ly)) ly = lx * Math.sign(ly);
      for (let j = Math.abs(lx) - 1; j > 0; j--) {
        this.personGoord.push([j * Math.sign(lx), (Math.abs(ly) - j) * Math.sign(ly), turnsNum]);
      }
      this.personGoord.push(v2);
      if (group) {
        turnsNum = (Math.abs(turnsNum) + 1) * Math.sign(turnsNum);
      }
    }
  }

  step: number = 0.015;
  Forward() {
    let v3 = new Vector3();
    v3.setFromMatrixColumn(this.group.matrix, 0);
    v3.crossVectors(this.group.up, v3);
    this.group.position.addScaledVector(v3, this.step);
  }

  EveryOneLookAtNearest() {
    for (let i = 0; i < this.group.children.length; i++) {
      let m = this.group.children[i];
      let min = 100;
      let minNpc: NPC;

      for (let i = 0; i < world.Items.length; i++) {
        let npc = world.Items[i];
        if (npc.value.distance > 3) continue;
        let personPos = m.getWorldPosition(new Vector3());
        let npcPos = npc.value.model.getWorldPosition(new Vector3());
        let distance = personPos.distanceTo(npcPos);

        if (distance < min) {
          min = distance;
          minNpc = npc.value;
        }
      }
      if (minNpc) {
        m.lookAt(minNpc.model.position);
      }
    }
  }

  oldS: number;
  async Attack(t) {
    let s = Math.trunc(t / 1000 / 1);
    if (s != this.oldS) {
      for (let i = 0; i < this.group.children.length; i++) {
        let m = this.group.children[i];
        let bullet = new Bullet(
          {
            modelUrl: `bullet`,
            scale: 0.0003,
            angle: Math.PI,
            mater: { color: new Color("#DDAA44") },
          },
          m
        );

        await bullet.Builder();
        render.mainScene.add(bullet.model);
      }
      this.oldS = s;
    }
  }

  Dispose() {
    this.behaviors.forEach((m) => {
      render.removeClockEvent(m);
    });
  }
}
